PWM in PIC16F616 using PWM module

In this tutorial we will see how to generate PWM using PWM module in PIC16F616

PIC16F616 has CCP module(Capture compare PWM module) which can be used to count frequency of input signal or use inbuilt comparator or generate PWM.

        
    #include <xc.h>

    // CONFIG
    #pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSCIO oscillator: I/O function on RA4/OSC2/CLKOUT pin, I/O function on RA5/OSC1/CLKIN)
    #pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
    #pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
    #pragma config MCLRE = ON       // MCLR Pin Function Select bit (MCLR pin function is MCLR)
    #pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
    #pragma config IOSCFS = 8MHZ    // Internal Oscillator Frequency Select bit (8 MHz)
    #pragma config BOREN = OFF      // Brown-out Reset Selection bits (BOR Disabled)
    
    #define Tout RA0
    
    unsigned long int PWM_freq = 8000UL; // min freq achievable is 4khz
    unsigned int duty_cycle = 816,result;
    unsigned char T0_count,T1H_count,T1L_count;
    
    _Bool check1,check2;
    
    //unsigned int off_count_calculator();
    
    void __interrupt () ISR(void)
    {
        //PORTAbits.RA4 = 1;
        if(TMR0IF)
        {
            T0IE = 0;
            TMR0IF = 0;
            
            //PORTAbits.RA4 = 1;
            Tout = 1U;
            //Tout = check1;
            //check1 = !check1;
            TMR0 = T0_count;
            TMR1L = T1L_count;
            TMR1H = T1H_count;
            T0IE = 1;
            TMR1IE = 1;
        }
        
        if(TMR1IF)
        {
            TMR1IE = 0;
            TMR1IF = 0;
            Tout = 0U;
            
        }
        if(ADIF)
        {
            ADIE = 0; // disable adc interrupt
            ADIF = 0; // clear adc interrupt flag
            if(!GO) // if conversion is complete
            {
                result = ADRESH;
                result = (result<<8) + ADRESL;
                //GO = 1;
            }
            ADIE = 1; // enable adc interrupt
        }
    }
    
    void ADC2_init()
    {
        ADIE = 0U;
        ADIF = 0U;
        ADFM = 1U; // right justified and vdd for analog voltage reference
        ADCON0 &= 0x1B; // select channel2 for adc conversion
        ADIE = 1;
    }
    
    void PWM_init(uint32_t freq)
    {
        uint8_t factor,i,temp;
        //GPIO_create(PORTC, 5, input, FALSE);
        GPIO_create(PORTC, 5, digital_output, FALSE);
        factor = (((cpu_clk>>2)/freq)/0xFF);
        if(factor == 0)
        {
            PR2 = (((cpu_clk>>2)/freq) - 1);
            T2CONbits.T2CKPS = 0U;
        }
        else if(factor < 4)
        {
            PR2 = (((cpu_clk>>4)/freq) - 1);
            T2CONbits.T2CKPS = 1U;
        }
        else
        {
            PR2 = (((cpu_clk>>6)/freq) - 1);
            T2CONbits.T2CKPS = 2U;
        }
        //PR2 = 0x50;
        temp = PR2;
        for(i = 0; i < 8; i++)
        {
            temp = temp>>1;
            if(!temp)
                break;
            res++;
        }
        CCP1CONbits.PM = 0;
        CCP1CONbits.CCP1M = 0xC;
        CCPR1L = (PR2>>1);
        CCP1CONbits.DCB = 3;
        PIE1bits.TMR2IE = 0U;
        PIR1bits.T2IF = 0U;
        PIE1bits.T2IE = 1U;
        T2CONbits.TMR2ON = 1;
        
        PIR1bits.T2IF = 0;
    }

    
    void main()
    {
        unsigned char count1 = 0,count2 = 4;
        INTCONbits.GIE = 1;
        INTCONbits.PEIE = 1;
        ADC2_init();
        while(1)
        {
        }
    }